import Dep from "./observer/dep";
import { observer } from "./observer/index";
import Watcher from "./observer/watcher";
import { nextTick } from "./utils/nextTick";

export function initState(vm) {
  let opts = vm.$options;
  //判断
  if (opts.props) {
    initProps();
  }
  if (opts.data) {
    initData(vm);
  }
  if (opts.watch) {
    initWatch(vm);
  }
  if (opts.computed) {
    initComputed(vm, opts.computed);
  }
  if (opts.methods) {
    initMethods(vm);
  }
}
//对data初始化
export function initData(vm) {
  //1.对象 2.函数
  let data = vm.$options.data;
  data = vm._data = typeof data === "function" ? data.call(vm) : data;
  //将data上的数据代理到vm（vue实列）上
  for (const key in data) {
    proxy(vm, "_data", key);
  }
  //data数据劫持
  observer(data); //data 两种情况 对象和数组
}
function proxy(vm, sourse, key) {
  Object.defineProperty(vm, key, {
    get() {
      return vm[sourse][key];
    },
    set(newValue) {
      vm[sourse][key] = newValue;
    },
  });
}
export function initProps() {}
export function initPinitWatchops() {}
export function initMethods(vm) {
  let methods = vm.$options.methods;
  if (methods) {
    for (const key in methods) {
      vm[key] = methods[key];
    }
  }
}
export function initComputed(vm, computed) {
  // 每个计算属性都需要一个watcher进行处理
  const watcher = (vm._computedWatchers = {});
  for (const key in computed) {
    //注意计算属性会有两种书写方式 对象和方法
    let userDef = computed[key];
    //获取get
    let getter = typeof userDef == "function" ? userDef : userDef.get; //watcher
    //给计算属性的每一个属性都要添加watcher
    watcher[key] = new Watcher(vm, getter, () => {}, { lazy: true }); //计算属性中的watcer 懒 的 用到才执行
    //defineReative
    defineComponent(vm, key, userDef);
  }
}
//劫持计算属性
let sharedPropDefinition = {};
function defineComponent(target, key, userDef) {
  sharedPropDefinition = {
    enumerable: true, //可枚举
    configurable: true, //
    get: () => {},
    set: () => {},
  };
  if (typeof userDef == "function") {
    sharedPropDefinition.get = createComputedGetter(key);
  } else {
    sharedPropDefinition.get = createComputedGetter(key);
    sharedPropDefinition.set = userDef.set;
  }
  Object.defineProperty(target, key, sharedPropDefinition);
  console.log(target);
}
//计算属性缓存
function createComputedGetter(key) {
  //返回用户 方法
  return function () {
    //dirty true时执行
    let watcher = this._computedWatchers[key];
    if (watcher) {
      if (watcher.dirty) {
        //执行get  求值
        watcher.evaluate(); //执行用户的方法
      }
      if (Dep.target) {
        watcher.depend(); //在计算属性的watcher收集页面的渲染的wahter
      }
      return watcher.value;
    }
  };
}
export function stateMixin(Vue) {
  //列队 1.vue自己的nextTick 2. 用户自己的
  Vue.prototype.$nextTick = function (cb) {
    //数据更新之后获取最新的don
    nextTick(cb);
  };
  Vue.prototype.$watch = function (exprOrfn, handler, options) {
    //watch的实现 1.渲染watcher 2.watch 走 watcher
    let watcher = new Watcher(this, exprOrfn, handler, {
      ...options,
      user: true,
    });
    if (options?.immediate) {
      handler.call(this);
    }
  };
}
function initWatch(vm) {
  let watch = vm.$options.watch;
  for (const key in watch) {
    let handler = watch[key];
    if (Array.isArray(handler)) {
      handler.forEach((item) => createrWatcher(vm, key, item));
    } else {
      //对象 字符串,函数
      createrWatcher(vm, key, handler);
    }
  }
}
//vm.$watch((=>{return 'a'})) 返回的就是watnher上的属性 user=false
function createrWatcher(vm, exprOrfn, handler, options) {
  //处理handler
  if (typeof handler === "object") {
    options = handler;
    handler = handler.handler; //得到函数
  }
  if (typeof handler === "string") {
    handler = vm[handler]; //字符串就调用实列的方法
  }
  return vm.$watch(exprOrfn, handler, options);
}
